/**
 * This is the jquery plugin for the data loading.
 * It is expected that data will be requested in a chunks.
 * The responsibility of server is to be able process the request and return the data in the right format.
 * Each request is a get or post type and contains the following parameters:
 * <ul>
 *   <li>from - from which record the selection should start (non negative integer)</li>
 *   <li>limit - limits the maximum number of returned records (non negative integer or null)</li>
 *   <li>code - code to ensure the request consistency (string)</li>
 * </ul>
 * The response JSON is expected to have same structure as the same example:
 * {numRecords : 100, code : 'ABCDE', records : [{...}, {...}, {...}]}
 * Where:
 * <ul>
 *   <li>numRecords - the total number of available records (non negative integer)</li>
 *   <li>
 *     code - the copy of the code which was received during request, empty string
 *       in case the request does not contains the code (string)
 *   </li>
 *   <li>records - the array with the selected record objects</li>
 * </ul>
 * When plugin finish the loading, function onLoadingDone is called.
 * This function needs to process the JSON with the structure:
 * {numRecords : 100, form : 0, limit : 500, records : [{...}, {...}, {...}]}
 * Where
 * <ul>
 *   <li>from - the copy of the value from options, setted by user</li>
 *   <li>limit - the copy of the value from options, setted by user</li>
 *   <li>numRecords - the total number of available records (non negative integer)</li>
 *   <li>records - the array with the selected record objects</li>
 * </ul>
 * 
 * @author radek.hecl
 * @version 2.0.0
 */
(function($){

  var DataLoader = this.DataLoader = $.dataLoader = function(options) {
    options = $.extend({}, this.defaults, options);
    options.from = parseInt(options.from);
    if (options.limit == '' || options.limit == null) {
      options.limit = null;
    }
    else {
      options.limit = parseInt(options.limit);
    }
    options.requestLimit = parseInt(options.requestLimit);
    
    var records = [];
    
    function constructResult(numRecords, records) {
      options.onLoadingDone({
          from       : options.from,
          limit      : options.limit,
          numRecords : numRecords,
          records    : records
      });
      if (options.onLoadingComplete) { options.onLoadingComplete(); }
    }
    
    function selectRecordsHandler(data) {
      for (var i = 0; i < data.records.length; ++i) {
        records.push(data.records[i]);
      }
      if (options.limit != null && records.length >= options.limit) {
        if (records.length == options.limit) {
          constructResult(data.numRecords, records);
        }
        else {
          var limitedRecords = [];
          for (var i = 0; i < options.limit; ++i) {
            limitedRecords.push(records[i]);
          }
          constructResult(data.numRecords, limitedRecords);
        }
      }
      else if (options.from + records.length >= data.numRecords) {
        constructResult(data.numRecords, records);
      }
      else {
        selectRecords(options.from + records.length, options.requestLimit);
      }
    }
    
    function selectRecords(from, limit) {
      var filter = $.extend({}, { from : parseInt(from), limit : parseInt(limit) }, options.requestData);
      options.errorReporter.getJSON(options.url, filter, selectRecordsHandler).
          error(function() {
            if (options.onLoadingError) { options.onLoadingError(); }
            if (options.onLoadingComplete) { options.onLoadingComplete(); }
          });
    }
    // run the plugin
    if (options.onLoadingStarted) { options.onLoadingStarted(); }
    selectRecords(options.from, options.requestLimit);
        
  };

  DataLoader.prototype = {
    defaults : {
      url               : '',                  // url from where the records will be loaded
      requestData       : {},                  // the addition data which are sends with the request
      from              : 0,                   // from which record the loading should start
      limit             : null,                // limit of the total loaded records (null for unlimited)
      requestLimit      : 100,                 // limit of the queried records per one http request - must be positive integer
      errorReporter     : null,                // error reporter which is used for the requests - mandatory
      
      /**
       * Callback function which is called whenever the loading started.
       * This is called before the first request data construction.
       */
      onLoadingStarted  : function() {},
      
      /**
       * Callback function which is called whenever the loading is done.
       * @param records object
       */
      onLoadingDone     : function(result) {},
      
      /**
       * Callback function which is called when there is an error during data loading.
       * @param object error object
       */
      onLoadingError    : function(error) {},
      
      /**
       * Callback function which is called whenever the loading is complete.
       * After onLoadingDone or onLoadingError.
       */
      onLoadingComplete : function() {}
    }
  };  

})(jQuery);
